package com.yoso.core.util;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;

import java.lang.reflect.Field;
import java.util.stream.Stream;

/**
 * 类转换工具
 * @author shizejin
 * @date 2023/11/28 09:55
 */
public class ConvertUtil {
    /**
     * 一个对象给另一个对象赋值时，将set,get方法(链式)打印在控制台上
     * @param sourceClass 源对象
     * @param sourceVarName 源对象的参数名，一般是convert方法中的参数名
     * @param targetClass 需要设值的目标对象
     * @author shizejin
     * @date 2023/11/09 13:35
     */
    public static void printBeanConvertToConsole(Class<?> sourceClass, String sourceVarName, Class<?> targetClass) {
        printBeanConvertToConsole(sourceClass, sourceVarName, targetClass, true);
    }

    /**
     * 一个对象给另一个对象赋值时，将set,get方法(链式)打印在控制台上
     *
     * @param sourceClass   源对象
     * @param targetClass   需要设值的目标对象
     * @author shizejin
     * @date 2023/11/09 13:34
     */
    public static void printBeanConvertToConsole(Class<?> sourceClass, Class<?> targetClass) {
        printBeanConvertToConsole(sourceClass, null, targetClass, true);
    }

    /**
     * 一个对象给另一个对象赋值时，将set,get方法打印在控制台上
     * 生成的条件：
     * 1.可以不是同一个类
     * 2.必须是相同字段名，且类型相同
     *
     * @param sourceClass   源对象
     * @param sourceVarName **.getName(), 源对象的参数名
     * @param targetClass   需要设值的目标对象
     * @param isChain       是否是链式的set,get
     * @author shizejin
     * @date 2023/11/09 13:34
     */
    public static void printBeanConvertToConsole(Class<?> sourceClass, String sourceVarName, Class<?> targetClass, Boolean isChain) {

        String className = targetClass.getSimpleName();
        if (StrUtil.isBlank(sourceVarName)) {
            sourceVarName = parseVarName(sourceClass);
        }
        String targetVarName = parseVarName(targetClass);
//        ep: Object object =
        String definedVar = className.concat(" ").concat(targetVarName).concat(" = ");

        StringBuilder builder = new StringBuilder();
//        ep: new Object();
        builder.append("new ").append(className).append("();");

        for (Field targetField : ReflectUtil.getFields(targetClass)) {
            String fieldName = targetField.getName();
            Field sourceField = ReflectUtil.getField(sourceClass, fieldName);
//            不是共有字段不设置，不是相同类型不设置
            if (ObjectUtil.isNull(sourceField) || sourceField.getType() != targetField.getType()) {
                continue;
            }
//            ep: sourceVar.getName()
            String getterName = sourceVarName.concat(".get").concat(StrUtil.upperFirst(fieldName)).concat("()");
//            ep: setName
            String setterName = "set".concat(StrUtil.upperFirst(fieldName));
//            ep: object.setName()
            builder.append(targetVarName).append(".").append(setterName).append("(").append(getterName).append(");");
        }

        String createObj = builder.toString();
//        ep: new InterfaceVo();interfaceVo.setId(myInterface.getId()); -> new InterfaceVo().setId(myInterface.getId());
        if (BooleanUtil.isTrue(isChain)) {
            createObj = StrUtil.replace(createObj, ";" + targetVarName, "");
        }
        System.out.println(definedVar + createObj);
    }

    /**
     * 判断变量名是否是关键字
     * @param var 变量名
     * @return boolean
     * @author shizejin
     * @date 2023/11/09 13:27
     */
    private static boolean isKeyWord(String var) {
        return Stream.of(
                "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
                "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float",
                "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
                "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp",
                "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void",
                "volatile", "while"
        ).anyMatch(keyword -> StrUtil.equals(keyword, var));
    }

    /**
     * 根据类解析成一个类的变量名
     * @param aClass 类
     * @return {@link String }
     * @author shizejin
     * @date 2023/11/09 13:27
     */
    private static String parseVarName(Class<?> aClass) {
        String className = aClass.getSimpleName();
        String varName = StrUtil.lowerFirst(className);
//        如果变量名是关键字，则需要区分
        if (isKeyWord(varName)) {
            varName = "a".concat(className);
        }
        return varName;
    }
}
